package com.itheima.ssm.dao;

import com.itheima.ssm.domain.Role;
import com.itheima.ssm.domain.UserInfo;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface IUserDao {
    @Select("select * from users where username=#{username}")
    @Results({
            @Result(id = true,property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "email",column = "email"),
            @Result(property = "password",column = "password"),
            @Result(property = "phoneNum",column = "phoneNum"),
            @Result(property = "status",column = "status"),
            /*
                封装role表的信息到这个list中，方便我们从UserInfo 实体Bean中找到Role从而找到角色，然后进行对这些角色的授权工作
                那么我们如何才能查询到Role表的信息呢? 我们知道User和Role之间是多对多的关系，所以我们采用中间表来存放两张表之间的
                外键彼此关联，通过UserInfo的id找到存放外键表中的Role的id，然后通过role的id找到Role表中对应id的role的数据信息
                这里使用内嵌子查询即可实现这样的操作
            */
            @Result(property = "roles",column = "id",javaType = java.util.List.class,many = @Many(select = "com.itheima.ssm.dao.IRoleDao.findRoleByUserId")),
    })
    public UserInfo findByUsername(String username) throws Exception;


    /**
     * 查询所有用户信息
     * @return
     */
    @Select("select * from users")
    public List<UserInfo> findAll() throws Exception;

    /**
     * 添加用户
     * @param userInfo
     * @throws Exception
     */
    @Insert("insert into users(email,username,password,phoneNum,status) values(#{email},#{username},#{password},#{phoneNum},#{status})")
    void save(UserInfo userInfo) throws Exception;

    /**
     * 根据用户id查询用户的详细信息
     * 通过userId找到到user的基本信息，然后找到其关联的role表的信息，封装到List<Role>中
     * 然后我们需要通过roleId查找到当前用户的权限信息，将其封装到Pemission对象中
     * users--->role--->pemession,这样的sql语句该如何编写
     * @param userId
     * @return
     * @throws Exception
     */
    @Select("select * from users where id = #{userId}")
    @Results({
            // 查询出role的信息，对于role中封装的pemession信息在IRoleDao中创建特定的方式来实现，分两个步骤实现
            @Result(id = true,property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "email",column = "email"),
            @Result(property = "password",column = "password"),
            @Result(property = "phoneNum",column = "phoneNum"),
            @Result(property = "status",column = "status"),
            /*
                封装role表的信息到这个list中，方便我们从UserInfo 实体Bean中找到Role从而找到角色，然后进行对这些角色的授权工作
                那么我们如何才能查询到Role表的信息呢? 我们知道User和Role之间是多对多的关系，所以我们采用中间表来存放两张表之间的
                外键彼此关联，通过UserInfo的id找到存放外键表中的Role的id，然后通过role的id找到Role表中对应id的role的数据信息
                这里使用内嵌子查询即可实现这样的操作
            */
            /*第一步：查询出role的信息*/
            @Result(property = "roles",column = "id",javaType = java.util.List.class,many = @Many(select = "com.itheima.ssm.dao.IRoleDao.findRoleByUserId")),
    })
    UserInfo findById(int userId) throws Exception;

    /**
     * 通过用户id找到用户还没有的角色
     * 内嵌一个子查询
     * @param userId
     * @return
     * @throws Exception
     */
    @Select("select * from role where id not in (select roleId from users_role id = #{userId})")
    List<Role> findOtherRoles(int userId) throws Exception;

    /**
     * 为id为userId的用户添加角色roleIds
     * 这里涉及使用mybatis实现批量插入数据的操作
     * 1. 传统的方式 insert into tableName() valuse(?,?,?,...),valuse(?,?,?,...),valuse(?,?,?,...)...
     *    局限性：已知添加到数量，显然这里我们并不知道前端传过来的id数组有多长，并且也不知道数组中具体的元素，所以这里并不适用
     *
     * 2. 适用mybatis中mapper文件中的循环标签实现<foreach><foreach/>  实际上就是在外层插入上添加一个循环而已
     * 例子：
     *      <insert id="insertBatch" >
     *          insert into person ( <include refid="Base_Column_List" /> )
     *          values
     *          <foreach collection="list" item="item" index="index" separator=",">
     *          (null,#{item.name},#{item.sex},#{item.address})
     *     </foreach>
     *      </insert>
     * 适用批量的好处：减少与数据库链接，提高效率
     * @param userId
     * @param roleIds
     * @throws Exception
     */
    @Insert("insert into users_role(userId,roleId) valuse(#{userId},#{roleId})")
    void addRoleToUser(@Param("userId") int userId, @Param("roleId") String roleIds) throws Exception;
}
